package utils;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

import dtos.UserDTO;

/**
 * Java bean for handling errors.
 * 
 * @author Szekely Krisztian-Vilmos
 * 
 */
@ManagedBean
@RequestScoped
public class ErrorBean {
	private Logger logger; 
	private String message;
	
	@PostConstruct
	private void init() {
		logger = Logger.getLogger(ErrorBean.class.getName());
		try {
			FileHandler fileHandler = new FileHandler(FacesContext.getCurrentInstance().getExternalContext().getRealPath("/logging.log"));
			fileHandler.setFormatter(new SimpleFormatter());
			logger.addHandler(fileHandler);
		} catch (IOException ex) {
			return;
		}
	}

	public Logger getLogger() {
		return logger;
	}

	public void setLogger(Logger logger) {
		this.logger = logger;
	}
	
	public String getMessage() {
		message = getError();
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	/**
	 * The occurred error is retrieved from the {@link FacesContext}, and a corresponding message is set. 
	 * This message will be displayed to the user.
	 * 
	 * @return A {@link String} containing the error message .
	 */
	private String getError() {
		Pattern pattern = Pattern.compile(".*exception.*",  Pattern.CASE_INSENSITIVE);
		Matcher matcher;
		StringBuffer sb = new StringBuffer();

		Map<String, Object> requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
		Iterator<Entry<String, Object>> it = requestMap.entrySet().iterator();
	    while (it.hasNext()) {
	        Map.Entry<String, Object> pairs = (Map.Entry<String, Object>)it.next();
	       
	        System.out.println(pairs.getKey() + " = " + pairs.getValue());
	        
	        matcher = pattern.matcher(pairs.getKey());
	        if (matcher.matches()) {
	    		handleException(requestMap.get(pairs.getKey()), sb);
	        }
	    }

		if (sb.toString().isEmpty()) {
			setMessage(sb);
		}
		return sb.toString();
	}

	/**
	 * The caught exception is checked and a corresponding message is set.
	 * 
	 * @param ex - the caught exception
	 * @param sb - the {@link StringBuffer} in witch we add error messages
	 */
	private void handleException(Object ex, StringBuffer sb) {
		if (null == ex) {
			return;
		}

		if ((ex instanceof Exception) || (ex instanceof RuntimeException)) {
			logger.log(Level.SEVERE, ((Throwable)ex).getMessage());
			setMessage(sb);
		}
	}

	/**
	 * A generic messag is set that will be displayed to the user.
	 * 
	 * @param sb - the {@link StringBuffer} in witch we add error messages
	 */
	private void setMessage(StringBuffer sb) {
		sb.append("The operation can't be performed.");
	}

	/**
	 * If an error occurred, before returning to normal operation 
	 * a check is performed to verify where the redirect can go to.  
	 */
	public void checkUser() {
		ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
		UserDTO user = (UserDTO) context.getSessionMap().get("loggedUser");
		
		try {
			if (user == null) {
				context.dispatch("/login.xhtml");
			} else {
				switch (user.getIdUsertype()) {
					case 1: 
						context.dispatch("/admin/mainAdmin.xhtml");
						break;
					case 2: 
						context.dispatch("/manager/mainManager.xhtml");
						break;
					case 3: 
						context.dispatch("/tech/mainTech.xhtml");
						break;
					case 4: 
						context.dispatch("/user/mainUser.xhtml");
						break;
				}
			}
		
		} catch (IOException ex) {
			return;
		}
	}
}
